package com.ovopark.firecar.utils

import android.util.SparseBooleanArray
import java.io.Serializable
import java.util.*

/**
 * List ContextUtils
 *
 * @author [Trinea](http://www.trinea.cn) 2011-7-22
 */
object ListUtils {
    /**
     * default join separator
     */
    const val DEFAULT_JOIN_SEPARATOR = ","

    /**
     * get size of list
     *
     *
     * <pre>
     * getSize(null)   =   0;
     * getSize({})     =   0;
     * getSize({1})    =   1;
    </pre> *
     *
     * @param <V>
     * @param sourceList
     * @return if list is null or empty, return 0, else return [List.size].
    </V> */
    fun <V:Any> getSize(sourceList: List<V>?): Int {
        return sourceList?.size ?: 0
    }

    /**
     * is null or its size is 0
     *
     *
     * <pre>
     * isEmpty(null)   =   true;
     * isEmpty({})     =   true;
     * isEmpty({1})    =   false;
    </pre> *
     *
     * @param <V>
     * @param sourceList
     * @return if list is null or its size is 0, return true, else return false.
    </V> */
    @JvmStatic
    fun <V:Any?> isEmpty(sourceList: List<V>?): Boolean {
        return sourceList == null || sourceList.size == 0
    }

    /**
     * compare two list
     *
     *
     * <pre>
     * isEquals(null, null) = true;
     * isEquals(new ArrayList&lt;String&gt;(), null) = false;
     * isEquals(null, new ArrayList&lt;String&gt;()) = false;
     * isEquals(new ArrayList&lt;String&gt;(), new ArrayList&lt;String&gt;()) = true;
    </pre> *
     *
     * @param <V>
     * @param actual
     * @param expected
     * @return
    </V> */
    fun <V:Any> isEquals(actual: ArrayList<V>?, expected: ArrayList<V>?): Boolean {
        if (actual == null) {
            return expected == null
        }
        if (expected == null) {
            return false
        }
        if (actual.size != expected.size) {
            return false
        }
        for (i in actual.indices) {
            if (!ObjectUtils.isEquals(actual[i], expected[i])) {
                return false
            }
        }
        return true
    }

    /**
     * join list to string
     *
     *
     * <pre>
     * join(null, '#')     =   "";
     * join({}, '#')       =   "";
     * join({a,b,c}, ' ')  =   "abc";
     * join({a,b,c}, '#')  =   "a#b#c";
    </pre> *
     *
     * @param list
     * @param separator
     * @return join list to string. if list is empty, return ""
     */
    fun join(list: List<String?>, separator: Char): String {
        return join(list, String(charArrayOf(separator)))
    }
    /**
     * join list to string. if separator is null, use [.DEFAULT_JOIN_SEPARATOR]
     *
     *
     * <pre>
     * join(null, "#")     =   "";
     * join({}, "#$")      =   "";
     * join({a,b,c}, null) =   "a,b,c";
     * join({a,b,c}, "")   =   "abc";
     * join({a,b,c}, "#")  =   "a#b#c";
     * join({a,b,c}, "#$") =   "a#$b#$c";
    </pre> *
     *
     * @param list
     * @param separator
     * @return join list to string with separator. if list is empty, return ""
     */
    /**
     * join list to string, separator is ","
     *
     *
     * <pre>
     * join(null)      =   "";
     * join({})        =   "";
     * join({a,b})     =   "a,b";
    </pre> *
     *
     * @param list
     * @return join list to string, separator is ",". if list is empty, return ""
     */
    @JvmOverloads
    fun join(list: List<String?>, separator: String? = DEFAULT_JOIN_SEPARATOR): String {
        var separator = separator
        if (isEmpty(list)) {
            return ""
        }
        if (separator == null) {
            separator = DEFAULT_JOIN_SEPARATOR
        }
        val joinStr = StringBuilder()
        for (i in list.indices) {
            joinStr.append(list[i])
            if (i != list.size - 1) {
                joinStr.append(separator)
            }
        }
        return joinStr.toString()
    }

    /**
     * add distinct entry to list
     *
     * @param <V>
     * @param sourceList
     * @param entry
     * @return if entry already exist in sourceList, return false, else add it and return true.
    </V> */
    fun <V:Any> addDistinctEntry(sourceList: MutableList<V>?, entry: V): Boolean {
        return if (sourceList != null && !sourceList.contains(entry)) sourceList.add(entry) else false
    }

    /**
     * add all distinct entry to list1 from list2
     *
     * @param <V>
     * @param sourceList
     * @param entryList
     * @return the count of entries be added
    </V> */
    fun <V:Any> addDistinctList(sourceList: MutableList<V>?, entryList: List<V>): Int {
        if (sourceList == null || isEmpty(entryList)) {
            return 0
        }
        val sourceCount = sourceList.size
        for (entry in entryList) {
            if (!sourceList.contains(entry)) {
                sourceList.add(entry)
            }
        }
        return sourceList.size - sourceCount
    }

    /**
     * remove duplicate entries in list
     *
     * @param <V>
     * @param sourceList
     * @return the count of entries be removed
    </V> */
    @JvmStatic
    fun <V:Any> distinctList(sourceList: MutableList<V>): Int {
        if (isEmpty(sourceList)) {
            return 0
        }
        val sourceCount = sourceList.size
        var sourceListSize = sourceList.size
        for (i in 0 until sourceListSize) {
            var j = i + 1
            while (j < sourceListSize) {
                if (sourceList[i] == sourceList[j]) {
                    sourceList.removeAt(j)
                    sourceListSize = sourceList.size
                    j--
                }
                j++
            }
        }
        return sourceCount - sourceList.size
    }

    /**
     * add not null entry to list
     *
     * @param sourceList
     * @param value
     * @return
     *  * if sourceList is null, return false
     *  * if value is null, return false
     *  * return [List.add]
     *
     */
    fun <V:Any> addListNotNullValue(sourceList: MutableList<V>?, value: V?): Boolean {
        return if (sourceList != null && value != null) sourceList.add(value) else false
    }

//    /**
//     * @see {@link ArrayUtils.getLast
//     */
//    fun <V:Any> getLast(sourceList: MutableList<V>?, value: V): V? {
//        return if (sourceList == null) null else getLast<Any>(
//            sourceList.toTypedArray(),
//            value,
//            true
//        ) as V?
//    }
//
//    /**
//     * @see {@link ArrayUtils.getNext
//     */
//    fun <V:Any> getNext(sourceList: List<V>?, value: V): V? {
//        return if (sourceList == null) null else getNext<Any>(
//            sourceList.toTypedArray(),
//            value,
//            true
//        ) as V?
//    }

    /**
     * invert list
     *
     * @param <V>
     * @param sourceList
     * @return
    </V> */
    fun <V:Any> invertList(sourceList: List<V>): List<V> {
        if (isEmpty(sourceList)) {
            return sourceList
        }
        val invertList: MutableList<V> = ArrayList(sourceList.size)
        for (i in sourceList.indices.reversed()) {
            invertList.add(sourceList[i])
        }
        return invertList
    }

    /**
     * 根据指定的位置从list集合中一次移除多个元素
     *
     * @param dealList     需要处理的list集合
     * @param positionList 需要移除某些位置的集合
     * @param <V>
     * @return
    </V> */
    fun <V:Any> iteratorDelete(dealList: MutableList<V>, positionList: List<Int>): List<V> {
        val sparseBooleanArray = SparseBooleanArray()
        for (position in positionList) {
            sparseBooleanArray.put(position, true)
        }
        val it = dealList.iterator()
        var i = 0
        while (it.hasNext()) {
            it.next()
            if (sparseBooleanArray[i]) {
                it.remove()
            }
            i++
        }
        return dealList
    }

    @JvmStatic
    fun clearList(list: MutableList<out Serializable?>) {
        if (!isEmpty(list)) list.clear()
    }

    /**
     * 重新打乱数组 每4个数据作为一个cell.
     * @param list
     * @param blockSize
     * @param <T>
     * @return
    </T> */
    fun <T> subList(list: List<T>?, blockSize: Int): List<List<T>> {
        val lists: MutableList<List<T>> = ArrayList()
        if (list != null && blockSize > 0) {
            val listSize = list.size
            if (listSize <= blockSize) {
                lists.add(list)
                return lists
            }
            val batchSize = listSize / blockSize
            val remain = listSize % blockSize
            for (i in 0 until batchSize) {
                val fromIndex = i * blockSize
                val toIndex = fromIndex + blockSize
                println("fromIndex=$fromIndex, toIndex=$toIndex")
                lists.add(list.subList(fromIndex, toIndex))
            }
            if (remain > 0) {
                println("fromIndex=" + (listSize - remain) + " , toIndex=" + listSize)
                lists.add(list.subList(listSize - remain, listSize))
            }
        }
        return lists
    }
}